package ssau.knyazev.fft.modules.threads;

import java.util.concurrent.CyclicBarrier;

import ssau.knyazev.core.Complex;

public class RowColThread implements Runnable{

	protected int idx;
	protected int idy;
	protected int uid;
	protected int blockX;
	protected int blockY;
	private Complex[][] data = null;
	private CyclicBarrier barrier = null;
	private Complex[] wlist = null;

	public RowColThread(CyclicBarrier barrier, int idx, int idy, int blockX, Complex[][] data, Complex[] wlist){
		this.idx = idx;
		this.idy = idy;
		this.uid = idy*blockX + idx;
		this.barrier = barrier;
		this.data = data;
		this.wlist = wlist;
		this.blockX = blockX;
	}
	
	public void run() {
		
		int N = data.length;
		int size = 0;
		for (int x = data.length; x > 1; x = x >> 1){
			size++;
		}
		int countThreads = barrier.getParties();
		//Calculates all rows
		for (int row = uid; row < data.length; row += countThreads){
			for (int q = 0; q < size; q++) {
				int step = (int) Math.pow(2, q);
				int step2 = step*2;
				boolean flag = true;
				for (int i = 0; i < N - step; i++) {
					flag = (i/step) % 2 > 0 ? false : true;
					if (flag) {
						Complex t = wlist[(i % (step2))*(N/step2)];
						butterfly(data[row][i], data[row][i + step], t);
					}
				}
			}
		}
		try {
			barrier.await();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		//Calculates cols
		for (int col = uid; col < data.length; col += countThreads){
			for (int q = 0; q < size; q++) {
				int step = (int) Math.pow(2, q);
				int step2 = step*2;
				boolean flag = true;
				for (int i = 0; i < N - step; i++) {
					flag = (i/step) % 2 > 0 ? false : true;
					if (flag) {
						Complex t = wlist[(i % (step2))*(N/step2)];
						butterfly(data[i][col], data[i + step][col], t);
					}
				}
			}
		}
		try {
			barrier.await();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
	}
	
	private static void butterfly(Complex a, Complex b, Complex w) {
		Complex anew = a.add(b.multy(w));
		Complex bnew = a.sub(b.multy(w));
		copyValues(a, anew);
		copyValues(b, bnew);
	}
	
	private static void copyValues(Complex a, Complex b) {
		a.setReal(b.getReal());
		a.setImg(b.getImg());
	}
	
}